package calao;

import static calao.util.Logger.ERROR;

import java.util.Locale;
import java.util.Vector;

import calao.client.Country;
import calao.client.EventLog;
import calao.client.Preferences;
import calao.client.SessionService;
import calao.client.MissingPermissionException;
import calao.client.SessionInfo;
import calao.client.WorkspaceInfo;
import calao.storage.RangeCondition;
import calao.storage.Record;
import calao.storage.Search;
import calao.util.Cursor;
import calao.util.Logger;

public class SessionServiceImpl 
extends DesktopServiceImpl 
implements SessionService 
{

	public void disconnect() 
	{
		this.getThreadLocalSession().close();
	}

	public SessionInfo getSessionInfo() 
	{
		return toInfo(getThreadLocalSession());
	}

	SessionInfo toInfo(Session session)
	{
		Vector<WorkspaceInfo> pathInfo = new Vector<WorkspaceInfo>();
		Workspace pathWS = session.getWorkspace();
		while (pathWS!=null) {
			pathInfo.add(WorkspaceServiceImpl.toInfo(pathWS));
			pathWS = pathWS.parent;
		}
		Vector<String> appNames = new Vector<String>();
		for (Application app : ws.server.getApplications()) {
			appNames.add(app.getName());
		}
		// case session was closed while building info
		if (pathInfo.isEmpty()) return null; 
		// normal case
		SessionInfo info = new SessionInfo(session.getGlobalUserId(), session.alias, 
				session.getWorkspace().path);
		info.setUserName(session.membership.name);
		info.setPreferences(getPreferences(session.getProperties()));
		info.setPermissions(
				session.permNames.toArray(new String[session.permNames.size()]));
		return info;
	}

	private Preferences getPreferences(Properties props)
	{
		Preferences prefs = new Preferences();
		prefs.setApplications(props.getStringListProperty(Properties.APPLICATIONS));
		prefs.setLanguage(props.getProperty(Properties.LANGUAGE));
		prefs.setTitle(props.getProperty(Properties.DESKTOP_TITLE));
		prefs.setFeatures(props.getStringListProperty(Properties.DESKTOP_FEATURES));
		prefs.setShortcuts(props.getStringListProperty(Properties.DESKTOP_SHORTCUTS));
		return prefs;
	}

	private void setPreferences(Properties props, Preferences prefs, boolean workspace)
	{
		set(props, Properties.LANGUAGE, prefs.getLanguage());
		set(props, Properties.DESKTOP_SHORTCUTS, prefs.getShortcuts());
		set(props, Properties.DESKTOP_TITLE, prefs.getTitle());
		if (workspace) {
			set(props, Properties.DESKTOP_FEATURES, prefs.getFeatures());
		}
	}

	void set(Properties props, String name, String value)
	{
		if (value!=null) props.setProperty(name, value);
	}

	void set(Properties props, String name, String[] value)
	{
		if (value!=null) props.setStringListProperty(name, value);
	}

	public void setUserPreferences(Preferences preferences) 
	{
		Properties props = getThreadLocalSession().getProperties();
		setPreferences(props, preferences, false);
		props.save();
	}

	public synchronized void setWorkspacePreferences(Preferences preferences) 
	throws MissingPermissionException 
	{
		check(ADMIN);
		Properties props = getWorkspace().properties;
		setPreferences(props, preferences, true);
		setApplications(preferences.getApplications());
		props.save();
	}
	
	void setApplications(String[] appNames)
	{
		Application.NameSet requestedApps = new Application.NameSet();
		for (String name : appNames) {
			Application app = ws.server.getApplication(name);
			if (app!=null) {
				requestedApps.add(name);
				ws.add(app);
			}
			else Logger.log(ERROR, "Cannot find application %s", name);
		}
		for (Application app : ws.getUsedApplications()) {
			if (!requestedApps.contains(app.name)) ws.remove(app);
		}
	}

	public synchronized Preferences getWorkspacePreferences() 
	{
		return getPreferences(getWorkspace().getProperties());
	}

	public EventLog[] getPreviousEvents(long eventId, int count) 
	{
		Search search = new Search(EventLogDB.TABLE);
		if (eventId!=0) search.add(new RangeCondition(EventLogDB.ID, eventId, null));
		Cursor<Record> cursor = getWorkspace().getStorage().listResults(search);
		Vector<EventLog> result = new Vector<EventLog>(count);
		try {
			while (cursor.next()) {
				Record rec = cursor.get();
				long eid = rec.getLong(EventLogDB.ID);
				if (eid==eventId) continue;
				if (count--==0) break;
				EventLog log = new EventLog(eid, EventLogDB.getTimeMinutes(eid),
						rec.get(EventLogDB.APPLICATION), rec.get(EventLogDB.EVENT_NAME),
						rec.getAll(EventLogDB.ARGV));
				Long guid = rec.get(EventLogDB.GUID);
				if (guid!=null) log.setGlobalUserId(guid);
				result.add(log);
			}
		}
		finally {
			cursor.close();
		}
		return result.toArray(new EventLog[result.size()]);
	}

	public Country[] listCountries() 
	{
		Locale locale = getThreadLocalSession().getLocale();
		String[] codes = Locale.getISOCountries();
		Country[] result = new Country[codes.length];
		for (int i=0; i<result.length; i++) {
			result[i] = new Country(codes[i], new Locale(locale.getLanguage(), 
					codes[i]).getDisplayCountry(locale));
		}
		return result;
	}

}
